use crate::error::Result;
use crate::llvm_backend::LLVMBackend;
use inkwell::{values::BasicValueEnum, AddressSpace, IntPredicate};

impl<'ctx> LLVMBackend<'ctx> {

    /// Check if a BasicValueEnum represents a string type (i8*)
    pub(in crate::llvm_backend) fn is_string_type(&self, value: &BasicValueEnum<'ctx>) -> bool {
        match value {
            BasicValueEnum::PointerValue(ptr) => {
                // Check if this is a pointer to i8 (string type)
                let ptr_type = ptr.get_type();
                // Compare with the expected string type (i8*)
                let expected_string_type = self
                    .context
                    .i8_type()
                    .ptr_type(inkwell::AddressSpace::default());
                ptr_type == expected_string_type
            }
            _ => false,
        }
    }


    /// Generate string content comparison using strcmp
    /// Returns 1 if strings are equal, 0 if not equal
    pub(in crate::llvm_backend) fn generate_string_content_compare(
        &mut self,
        left: BasicValueEnum<'ctx>,
        right: BasicValueEnum<'ctx>,
    ) -> Result<BasicValueEnum<'ctx>> {
        // Both operands should be pointer values (i8*)
        let left_ptr = left.into_pointer_value();
        let right_ptr = right.into_pointer_value();

        // Get or create strcmp function
        let i8_ptr_type = self.context.i8_type().ptr_type(AddressSpace::default());
        let i32_type = self.context.i32_type();
        let strcmp_fn_type = i32_type.fn_type(&[i8_ptr_type.into(), i8_ptr_type.into()], false);

        let strcmp_fn = if let Some(func) = self.module.get_function("strcmp") {
            func
        } else {
            self.module.add_function("strcmp", strcmp_fn_type, None)
        };

        // Call strcmp(left, right)
        let cmp_result = self
            .builder
            .build_call(
                strcmp_fn,
                &[left_ptr.into(), right_ptr.into()],
                "strcmp_result",
            )?
            .try_as_basic_value()
            .left()
            .unwrap()
            .into_int_value();

        // strcmp returns 0 if strings are equal, non-zero if different
        // We want to return 1 for equal, 0 for different
        let zero = i32_type.const_int(0, false);
        let one = i32_type.const_int(1, false);
        let is_equal = self.builder.build_int_compare(
            IntPredicate::EQ,
            cmp_result,
            zero,
            "is_equal",
        )?;

        // Convert i1 to i32: 1 if equal, 0 if not equal
        let result = self
            .builder
            .build_select(is_equal, one, zero, "string_compare_result")?;

        Ok(result.into())
    }
}
